﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using System.IO;
using Db4objects.Db4o.Config;
using Aga.Psad.Mvc.Services.Dtos;

namespace Aga.Informatizacion.Documentos.HOPE
{
    public partial class CargaManual : Form
    {
        private const int CLIENTE_OTRO = 1;
        private string imagesFolder;
        private IObjectContainer container;
        private Session sessionActual;
        private int LastSelectedIndex = -1;

        protected CargaManual()
        {
            InitializeComponent();

            // creo el container de Db4o
            IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();
            config.Common.ObjectClass(typeof(Session)).CascadeOnUpdate(true);
            container = Db4oEmbedded.OpenFile(config, "CargaManualHope.yap");

            Load += new EventHandler(CargaManual_Load);

        }

        void CargaManual_Load(object sender, EventArgs e)
        {
            // intento obtener la session guardada para esa carpeta
            sessionActual = (from Session s in container
                            where s.CarpetaOrigen.Equals(imagesFolder)
                            select s).FirstOrDefault();

            // si no habia ninguna session asociada a la carpeta... creo una nueva
            if (sessionActual == null)
                sessionActual = new Session(imagesFolder);

            // cargo los archivos (nuevos solamente)
            sessionActual.LoadArchivos();

            // guardo la session
            container.Store(sessionActual);

            // guardo los cambios pendientes
            container.Commit();

            // cargo los combos
            LoadCombos();

            // cargo la view de los archivos
            LoadView();
        }

        private void LoadCombos()
        {
            DocumentoDataServiceClient client = new DocumentoDataServiceClient();

            var tipos = client.ObtenerTiposDeDocumento();

            // cargo los items del combo
            ddlTiposDocumentos.Items.Clear();
            ddlTiposDocumentos.DataSource = tipos;
            ddlTiposDocumentos.DisplayMember = "Nombre";
            ddlTiposDocumentos.ValueMember = "Id";

            // obtengo los clientes
            var clientes = client.ObtenerClientesPorTipo(CLIENTE_OTRO);
            
            // cargo los items del combo
            ddlClientes.Items.Clear();
            ddlClientes.DataSource = clientes;
            ddlClientes.DisplayMember = "RazonSocial";
            ddlClientes.ValueMember = "Id";

            client.Close();
        }

        private void LoadView()
        {
            // limpio la lista
            lsvArchivos.Items.Clear();

            // cargo los archivos
            foreach (var item in sessionActual.Archivos)
                lsvArchivos.Items.Add(
                    new ListViewItem(
                        new string []
                        {
                            item.NombreOriginal,
                            item.Documento != null ? item.Documento.Nombre : "",
                            item.Documento != null ? item.Documento.NumeroDesde : "",
                            item.Documento != null ? item.Documento.NumeroHasta : "",
                            item.Documento != null ? item.Documento.Caja.ToString() : "",
                            item.Documento != null ? item.Documento.Lote.ToString() : "",
                            item.Documento != null ? item.Documento.Detalles : "",
                            item.NombreDestino,
                            item.Documento != null ? item.Documento.Id.ToString() : "",
                            item.Id.ToString(),
                            item.Documento != null ? item.Documento.ClienteNombre : "",
                            item.Documento != null ? item.Documento.DocumentoTipoNombre : ""
                        }));
        }

        /// <summary>
        /// Este metodo se encarga de mostrar una imagen en el panel
        /// principal de la aplicacion
        /// </summary>
        /// <param name="imagePath">Path de la imagen a mostrar</param>
        private void ShowImage(string imageName)
        {
            Image image = Image.FromFile(Path.Combine(sessionActual.CarpetaOrigen, imageName));
            pbxImagenActual.Width = image.Width;
            pbxImagenActual.Height = image.Height;
            pbxImagenActual.Image = image;
        }

        /// <summary>
        /// Contructor public de la clase. Requiere que le indiquen para que carpeta se 
        /// efectua el proceso de carga manual
        /// </summary>
        /// <param name="imagesFolder">Ruta a la carpeta de imagenes</param>
        public CargaManual(string imagesFolder)
            : this()
        {
            this.imagesFolder = imagesFolder;
        }

        /// <summary>
        /// Evento de close del form
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            // cierro el container de Db4o
            container.Close();

            base.OnClosed(e);
        }

        private void lsvArchivos_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            string nombreArchivo = e.Item.SubItems[0].Text;

            // obtengo el archivo
            Archivo archivo = sessionActual.GetArchivo(nombreArchivo);

            // si tiene un documento asociado, muestro los datos
            if (archivo.Documento != null)
            {
                txtNombre.Text = archivo.Documento.Nombre;
                txtNumeroDesde.Text = archivo.Documento.NumeroDesde.ToString();
                txtNumeroHasta.Text = (!String.IsNullOrEmpty(archivo.Documento.NumeroHasta) ? archivo.Documento.NumeroHasta : "");
                txtCaja.Text = archivo.Documento.Caja.ToString();
                txtLote.Text = (archivo.Documento.Lote.HasValue ? archivo.Documento.Lote.Value.ToString() : "");
                txtDetalle.Text = archivo.Documento.Detalles;
            }
            //else
            //{
            //    txtNombre.Text = "";
            //    txtNumeroDesde.Text = "";
            //    txtNumeroHasta.Text = "";
            //    txtCaja.Text = "";
            //    txtLote.Text = "";
            //    txtDetalle.Text = "";
            //}

            ShowImage(nombreArchivo);
        }

        private void btnAsociarDocumento_Click(object sender, EventArgs e)
        {
            // valido los datos ingresados
            int caja;
            if (!int.TryParse(txtCaja.Text, out caja))
            {
                MessageBox.Show("Debe ingresar un número de caja.",
                                    "Error de datos",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
                return;
            }

            string numeroDesde = txtNumeroDesde.Text;
            if (numeroDesde.Length == 0)
            {
                MessageBox.Show("Debe ingresar un numero desde.",
                                    "Error de datos",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
                return;
            }

            // obtengo los datos de la pantalla
            string nombre = txtNombre.Text;
            string numeroHasta = txtNumeroHasta.Text;
            int? lote = TryGetNullableValue(txtLote);
            string detalles = txtDetalle.Text;

            int clienteId = (int)ddlClientes.SelectedValue;
            string clienteNombre = (ddlClientes.SelectedItem as ClienteDto).RazonSocial;
            int documentoTipoId = (int)ddlTiposDocumentos.SelectedValue;
            string documentoTipoNombre = (ddlTiposDocumentos.SelectedItem as TipoDocumentoDto).Nombre;

            // intento obtener el documento si ya existe
            Documento doc = sessionActual.GetDocumento(clienteId, documentoTipoId, numeroDesde, caja);

            if (doc == null)
            {
                // creo el documento
                doc = new Documento()
                {
                    Nombre = nombre,
                    NumeroDesde = numeroDesde,
                    NumeroHasta = numeroHasta,
                    Caja = caja,
                    Lote = lote,
                    Detalles = detalles,
                    ClienteId = clienteId,
                    ClienteNombre = clienteNombre,
                    DocumentoTipoId = documentoTipoId,
                    DocumentoTipoNombre = documentoTipoNombre
                };

                // le agrego el documento a la session
                sessionActual.AgregarDocumento(doc);

            }
            else
            {
                doc.Nombre = nombre;
                doc.NumeroDesde = numeroDesde;
                doc.NumeroHasta = numeroHasta;
                doc.Caja = caja;
                doc.Lote = lote;
                doc.Detalles = detalles;
                doc.ClienteId = clienteId;
                doc.ClienteNombre = clienteNombre;
                doc.DocumentoTipoId = documentoTipoId;
                doc.DocumentoTipoNombre = documentoTipoNombre;
            }


            foreach (var item in lsvArchivos.CheckedItems)
            {
                // obtengo el archivo
                Archivo archivo = sessionActual.GetArchivo((item as ListViewItem).SubItems[0].Text);

                // asocio el archivo al documento
                sessionActual.AsociarArchivoConDocumento(archivo, doc);
            }

            // guardo la session
            container.Store(sessionActual);

            // guardo los cambios pendientes
            container.Commit();

            // limpio el form
            txtNombre.Text = "";
            txtNumeroDesde.Text = "";
            txtNumeroHasta.Text = "";
            //txtCaja.Text = "";
            //txtLote.Text = "";
            txtDetalle.Text = "";

            // muestro los cambios
            LoadView();

            RestoreLastItemPosition();
        }

        private int? TryGetNullableValue(TextBox control)
        {
            int value;
            if (int.TryParse(control.Text, out value))
                return new Nullable<int>(value);
            else
                return new Nullable<int>();
        }

        private void btnSubirCambios_Click(object sender, EventArgs e)
        {
            string destinationFolder = ConfiguracionHOPE.CarpetaDestino;

            // creo el proxy del servicio
            DocumentoDataServiceClient client = new DocumentoDataServiceClient();
            
            foreach (Documento documento in sessionActual.Documentos)
            {
                // chequeo si el documento existe
                DocumentoDto docDto = null;
                if (documento.Id > 0)
                    docDto = client.ObtenerDocumentoById(documento.Id);
                else
                    docDto = client.ObtenerDocumento(documento.ClienteId, documento.DocumentoTipoId, documento.NumeroDesde.ToString(), documento.Caja);

                // si no existe, lo creo y lo guardo
                if (docDto == null)
                {
                    // cargo el dto del documento
                    docDto = new DocumentoDto()
                    {
                        ClienteId = documento.ClienteId,
                        TipoDocumentoId = documento.DocumentoTipoId,
                        Nombre = documento.Nombre,
                        NumeroDesde = documento.NumeroDesde,
                        NumeroHasta = documento.NumeroHasta,
                        Caja = documento.Caja,
                        Lote = documento.Lote,
                        Detalle = documento.Detalles
                    };

                    // lo guardo y le obtengo el id
                    documento.Id = docDto.Id = client.NuevoDocumento(docDto);
                }
                else
                {
                    // si existe, lo actualizo
                    docDto.ClienteId = documento.ClienteId;
                    docDto.TipoDocumentoId = documento.DocumentoTipoId;
                    docDto.Nombre = documento.Nombre;
                    docDto.NumeroDesde = documento.NumeroDesde;
                    docDto.NumeroHasta = documento.NumeroHasta;
                    docDto.Caja = documento.Caja;
                    docDto.Lote = documento.Lote;
                    docDto.Detalle = documento.Detalles;

                    // lo guardo y le obtengo el id
                    client.ActualizarDocumento(docDto);
                    documento.Id = docDto.Id;
                }

                int cantidadImagenes = client.ObtenerCantidadImagenesDocumento(docDto.Id);

                for (int indiceArchivo = cantidadImagenes; indiceArchivo < (documento.Archivos.Count + cantidadImagenes); indiceArchivo++)
                {
                    Archivo archivo = documento.Archivos[indiceArchivo - cantidadImagenes];

                    // si ya subi esa imagen... no la vuelvo a subir
                    if (archivo.Id.Equals(-1))
                    {
                        // le pongo el nombre destino a la imagen
                        archivo.NombreDestino = string.Format("{0}_{1}_{2}.jpg", documento.Id, documento.NumeroDesde, indiceArchivo+1);

                        // copio el archivo fisicamente
                        CopiarArchivo(archivo.NombreOriginal, archivo.NombreDestino);

                        // agrego la imagen en el server
                        archivo.Id = client.NuevaImagen(
                            new ImagenDto()
                            {
                                DocumentoId = documento.Id,
                                Nombre = archivo.NombreDestino
                            });
                    }
                }

            }

            // cierro la conexion
            client.Close();

            // guardo la session
            container.Store(sessionActual);

            // guardo los cambios pendientes
            container.Commit();

            // regargo la vista
            LoadView();

            RestoreLastItemPosition();
        }

        private void RestoreLastItemPosition()
        {
            if (LastSelectedIndex > -1)
            {
                this.lsvArchivos.TopItem = this.lsvArchivos.Items[LastSelectedIndex];
                this.lsvArchivos.Focus();
            }
        }

        private void CopiarArchivo(string origen, string destino)
        {
            try
            {
                File.Copy(
                    Path.Combine(sessionActual.CarpetaOrigen, origen),
                    Path.Combine(ConfiguracionHOPE.CarpetaDestino, destino)
                    );
            }
            catch (UnauthorizedAccessException authEx)
            {
                MessageBox.Show(
                    "El usuario parece no tener permisos para efectuar la copia de archivos.\nPor favor, contacte al administrador del sistema.",
                    "Error de permisos",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation,
                    MessageBoxDefaultButton.Button1);
            }
            catch (DirectoryNotFoundException dirEx)
            {
                MessageBox.Show(
                    "La carpeta destino de la copia de archivos no existe.\nPor favor, contacte al administrador del sistema.",
                    "Error de carpetas",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation,
                    MessageBoxDefaultButton.Button1);
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    "Ocurrio un error intentando copiar los archivos.\nPor favor, contacte al administrador del sistema.",
                    "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation,
                    MessageBoxDefaultButton.Button1);
            }
        }

        private void lsvArchivos_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.lsvArchivos.SelectedIndices.Count > 0)
                this.LastSelectedIndex = this.lsvArchivos.SelectedIndices.Cast<int>().Last();
            else
                this.LastSelectedIndex = -1;
        }
    }
}
